using Mapster;
using Microsoft.AspNetCore.Http;
using Quartz;
using SqlSugar;
using QiAdmin.Core;
using QiAdmin.Core.Models;
using QiAdmin.Core.Services;
using QiAdmin.Core.Services.Log;
using QiAdmin.Core.Services.Quartz;
using QiAdmin.Core.Services.QuartzService;
using QiAdmin.Core.Services.Token;
using QiAdmin.Entity;
using QiAdmin.Model.Dtos;
using QiAdmin.Model.Dtos.Input;
using QiAdmin.Model.Dtos.Output;
using QiAdmin.Repository.Repository;
using QiAdmin.Service.IService;
using ICacheService = QiAdmin.Core.Services.Cache.ICacheService;

namespace QiAdmin.Service.Service
{
    /// <summary>
    /// TSysTask Service
    /// </summary>
    public class TSysTaskService : BaseService<TSysTask, TSysTask_IN, TSysTask_OUT>, ITSysTaskService
    {
        readonly TSysTaskRepository _tSysTaskRepository;
        readonly QuartzFactory _quartzFactory;

        public TSysTaskService(ILogService logService,
            ITokenService tokenService, ICacheService cacheService, IHttpContextAccessor httpContextAccessor, TSysTaskRepository tSysTaskRepository, QuartzFactory quartzFactory) : base(logService, tokenService, cacheService, httpContextAccessor.HttpContext)
        {
            _tSysTaskRepository = tSysTaskRepository;
            _quartzFactory = quartzFactory;
        }

        #region 增删改查-自动生成

        /// <summary>
        /// 创建默认条件
        /// </summary>
        /// <returns></returns>
        public Expressionable<TSysTask> CreateExp()
        {
            var exp = Expressionable.Create<TSysTask>();
            var (dataRang, permissions) = GetUserPermission();
            switch (dataRang)
            {
                case DataRang.All:
                    break;
                case DataRang.Dept:
                    exp.And(t => t.DeptId == Token.UserDept);
                    break;
                case DataRang.DeptAndBelow:
                    exp.And(t => GetRecursiveDept().Contains(t.DeptId));
                    break;
                case DataRang.Self:
                    exp.And(t => t.SysCreateUser == Token.UserId);
                    break;
                case DataRang.Custom:
                    exp.And(t => permissions.Contains(t.DeptId));
                    break;
            }
            return exp;
        }

        /// <summary>
        /// 新增单条
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult Add(TSysTask_IN input)
        {
            ITenant tenant = _tSysTaskRepository.AsTenant();
            try
            {
                tenant.BeginTran();
                var model = input.Adapt<TSysTask>();
                model.StartTime = model.StartTime == DateTime.MinValue ? null : model.StartTime;
                model.EndTime = model.EndTime == DateTime.MinValue ? null : model.EndTime;
                int Id = _tSysTaskRepository.InsertReturnIdentity(model);
                AddJob(input);
                tenant.CommitTran();
                return CommonResult.Success;
            }
            catch
            {
                tenant.RollbackTran();
                return CommonResult.Error;
            }
        }

        /// <summary>
        /// 新增多条
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult AddRange(List<TSysTask_IN> input)
        {
            var list = input.Adapt<List<TSysTask>>();
            var result = _tSysTaskRepository.InsertRange(list);
            return CommonResult.Convert(result);
        }

        /// <summary>
        /// 编辑
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult Edit(TSysTask_IN input)
        {
            ITenant tenant = _tSysTaskRepository.AsTenant();
            try
            {
                tenant.BeginTran();
                var exp = CreateExp();
                exp.And(t => t.Id == input.Id);

                var model = input.Adapt<TSysTask>();
                model.StartTime = model.StartTime == DateTime.MinValue ? null : model.StartTime;
                model.EndTime = model.EndTime == DateTime.MinValue ? null : model.EndTime;

                var result = _tSysTaskRepository.UpdateAndIgnore(model, exp.ToExpression());
                _quartzFactory.RemoveJob(new JobKey(model.Name, model.ClassName)).Wait();
                AddJob(input);

                tenant.CommitTran();
                return CommonResult.Convert(result);
            }
            catch
            {
                tenant.RollbackTran();
                return CommonResult.Error;
            }


        }

        /// <summary>
        /// 获取单条
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult<TSysTask_OUT> Get(TSysTask_IN input)
        {
            var exp = CreateExp();
            exp.And(t => t.Id == input.Id);

            var result = _tSysTaskRepository.GetFirst(exp.ToExpression()).Adapt<TSysTask_OUT>();
            return new CommonResult<TSysTask_OUT>(result);
        }

        /// <summary>
        /// 分页获取
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult<PageOutput<TSysTask_OUT>> GetPageList(TSysTask_IN input)
        {
            var exp = CreateExp();

            exp.AndIF(input.StartQueryTime != DateTime.MinValue, t => t.SysCreateTime >= input.StartQueryTime.Date);
            exp.AndIF(input.EndQueryTime != DateTime.MinValue, t => t.SysCreateTime < input.EndQueryTime.Date.AddDays(1));

            exp.AndIF(!string.IsNullOrEmpty(input.Name), t => t.Name.Contains(input.Name));


            PageOutput<TSysTask_OUT> pageOutput = new PageOutput<TSysTask_OUT>();
            PageModel pageModel = new() { PageIndex = input.PageIndex, PageSize = input.PageSize };

            pageOutput.Data = _tSysTaskRepository.AsQueryable().Where(exp.ToExpression()).OrderByDescending(t => t.Id).Select(s => new TSysTask_OUT
            {
                Id = s.Id,
                SysCreateTime = s.SysCreateTime,
                Status = s.Status,
                ClassName = s.ClassName,
                Name = s.Name,
                LastRunTime = SqlFunc.Subqueryable<TSysTaskLog>().Where(l => l.TaskId == s.Id).Select(l => SqlFunc.AggregateMax(l.SysCreateTime))
            }).ToPageList(pageModel.PageIndex, pageModel.PageSize).ToList();
            pageOutput.DataCount = pageModel.TotalCount;

            return new CommonResult<PageOutput<TSysTask_OUT>>(pageOutput);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult Remove(TSysTask_IN input)
        {

            ITenant tenant = _tSysTaskRepository.AsTenant();
            try
            {
                var exp = CreateExp();
                exp.And(t => t.Id == input.Id);
                var model = _tSysTaskRepository.GetFirst(exp.ToExpression());
                var result = _tSysTaskRepository.Delete(model);
                _quartzFactory.RemoveJob(new JobKey(model.Name, model.ClassName)).Wait();
                tenant.CommitTran();
                return CommonResult.Convert(result);
            }
            catch
            {
                tenant.RollbackTran();
                return CommonResult.Error;
            }
        }

        /// <summary>
        /// 删除多条
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public CommonResult RemoveRange(List<TSysTask_IN> input)
        {
            ITenant tenant = _tSysTaskRepository.AsTenant();
            try
            {
                var exp = CreateExp();
                exp.And(t => input.Select(s => s.Id).Contains(t.Id));

                var tasks = _tSysTaskRepository.GetList(exp.ToExpression());

                var result = _tSysTaskRepository.Delete(exp.ToExpression());

                foreach (var task in tasks)
                {
                    _quartzFactory.RemoveJob(new JobKey(task.Name, task.ClassName)).Wait();
                }
                tenant.CommitTran();
                return CommonResult.Convert(result);
            }
            catch
            {
                tenant.RollbackTran();
                return CommonResult.Error;
            }

        }

        #endregion


        private void AddJob(TSysTask_IN input)
        {
            if (input.Status)
            {
                input.StartTime = input.StartTime == DateTime.MinValue ? null : input.StartTime;
                input.EndTime = input.EndTime == DateTime.MinValue ? null : input.EndTime;

                JobDataMap jobData = new JobDataMap();
                var paras = input.Param.Split("##", StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < paras.Length; i++)
                {
                    jobData.Add("Param_" + i, paras[i]);
                }
                JobModel jobModel = new JobModel
                {
                    JobName = input.Id.ToString(),
                    JobGroup = input.ClassName,
                    TriggerName = input.Id + "Trigger",
                    TriggerGroup = input.ClassName + "Trigger",
                    IsSimpleSchedule = false,
                    StartTime = input.StartTime,
                    EndTime = input.EndTime,
                    CronExpression = input.Cron,
                    JobData = jobData
                };
                _quartzFactory.Add<AssemblyService>(jobModel);
            }
        }

        /// <summary>
        /// 从数据库恢复所有任务
        /// </summary>
        /// <returns></returns>
        public CommonResult Recover()
        {
            var tasks = _tSysTaskRepository.GetList(t => t.Status).Adapt<List<TSysTask_IN>>();
            foreach (var task in tasks)
            {
                _quartzFactory.RemoveJob(new JobKey(task.Name, task.ClassName)).Wait();
                AddJob(task);
            }
            return CommonResult.Success;
        }

        public CommonResult RunTask(TSysTask_IN input)
        {
            var task = Get(input).Result;
            if (!task.Status)
            {
                return CommonResult.Convert(false, "该任务已禁用");
            }
            _quartzFactory.Run(new JobKey(task.Name, task.ClassName)).Wait();
            return CommonResult.Success;
        }
    }
}
